export default /* glsl */`
varying vec2 vUv;
uniform mat3 uvTransform;

attribute vec3 core;
attribute vec3 frenetUp;
attribute vec3 direction;
uniform float radius;
uniform bool imgFacingCamera;

vec3 applyQuaternion(vec3 point, vec4 q) {
    float qx = q.x;
    float qy = q.y;
    float qz = q.z;
    float qw = q.w;
    float x = point.x;
    float y = point.y;
    float z = point.z;
    // calculate quat * vector
    float ix = qw * x + qy * z - qz * y;
    float iy = qw * y + qz * x - qx * z;
    float iz = qw * z + qx * y - qy * x;
    float iw = -qx * x - qy * y - qz * z;
    
    // calculate result * inverse quat
    x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
    y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
    z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
    return vec3(x, y, z);
}

vec4 createQuaternionByAxisAngle(vec3 axis, float angle) {
    float halfAngle = angle * 0.5;
    float s = sin(halfAngle);
    float qx = axis.x * s;
    float qy = axis.y * s;
    float qz = axis.z * s;
    float qw = cos(halfAngle);
    return vec4(qx, qy, qz, qw);
}

void main() {
    vUv = ( uvTransform * vec3( uv, 1 ) ).xy;
    vec3 pos = core + normal*radius;
    vec3 toCamera = cameraPosition - core;
    
    if (imgFacingCamera) {
        vec3 up = frenetUp;
        vec3 planeNormal = normalize(cross(up, direction) );
        float planeConst = -dot(core, planeNormal);
        float dist = dot(planeNormal, cameraPosition) + planeConst;
        float len = length(toCamera);
        float sign = -1.0;
        if (dot(up, toCamera) < 0.0) {
            sign = 1.0;
        }
        float phi = asin(sign * dist / len);
        // float phi = 3.1415926 / 6.0;
        vec4 quaternion = createQuaternionByAxisAngle(direction, phi);
        pos = applyQuaternion(normal*radius, quaternion);
        pos = pos + core;
    }
    gl_Position = projectionMatrix * modelViewMatrix * vec4( pos, 1.0 );
}
    `;
